package com.inforim.c10;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.rmi.RemoteException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.axis.AxisFault;
import org.apache.axis.encoding.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.cognos.developer.schemas.bibus._3.AsynchDetail;
import com.cognos.developer.schemas.bibus._3.AsynchDetailParameters;
import com.cognos.developer.schemas.bibus._3.AsynchDetailReportObject;
import com.cognos.developer.schemas.bibus._3.AsynchDetailReportOutput;
import com.cognos.developer.schemas.bibus._3.AsynchDetailReportStatus;
import com.cognos.developer.schemas.bibus._3.AsynchDetailReportStatusEnum;
import com.cognos.developer.schemas.bibus._3.AsynchOptionEnum;
import com.cognos.developer.schemas.bibus._3.AsynchOptionInt;
import com.cognos.developer.schemas.bibus._3.AsynchReply;
import com.cognos.developer.schemas.bibus._3.AsynchReplyStatusEnum;
import com.cognos.developer.schemas.bibus._3.AsynchSecondaryRequest;
import com.cognos.developer.schemas.bibus._3.AsynchSpecification;
import com.cognos.developer.schemas.bibus._3.AuthoredReport;
import com.cognos.developer.schemas.bibus._3.BaseClass;
import com.cognos.developer.schemas.bibus._3.BaseParameter;
import com.cognos.developer.schemas.bibus._3.ContentManagerServiceStub;
import com.cognos.developer.schemas.bibus._3.Graphic;
import com.cognos.developer.schemas.bibus._3.Option;
import com.cognos.developer.schemas.bibus._3.Output;
import com.cognos.developer.schemas.bibus._3.OutputEncapsulationEnum;
import com.cognos.developer.schemas.bibus._3.Parameter;
import com.cognos.developer.schemas.bibus._3.ParameterValue;
import com.cognos.developer.schemas.bibus._3.ParmValueItem;
import com.cognos.developer.schemas.bibus._3.PropEnum;
import com.cognos.developer.schemas.bibus._3.QueryOptions;
import com.cognos.developer.schemas.bibus._3.ReportServiceReportSpecification;
import com.cognos.developer.schemas.bibus._3.ReportServiceStub;
import com.cognos.developer.schemas.bibus._3.RunOptionBoolean;
import com.cognos.developer.schemas.bibus._3.RunOptionEnum;
import com.cognos.developer.schemas.bibus._3.RunOptionOutputEncapsulation;
import com.cognos.developer.schemas.bibus._3.RunOptionStringArray;
import com.cognos.developer.schemas.bibus._3.SearchPathSingleObject;
import com.cognos.developer.schemas.bibus._3.SimpleParmValueItem;
import com.cognos.developer.schemas.bibus._3.Sort;
import com.cognos.developer.schemas.bibus._3.Specification;
import com.inforim.cognos.CognosClient;
import com.inforim.cognos.plugins.CognosReportPlugin;
import com.inforim.cognos.utils.CognosHelper;

public class CognosReportPluginImpl implements CognosReportPlugin {
//	List<CogUser> userlist = new ArrayList();

	  
	static Log log = LogFactory.getLog(CognosReportPluginImpl.class);

	protected static boolean hasSecondaryRequest(AsynchReply response,
			String secondaryRequest) {
		AsynchSecondaryRequest[] secondaryRequests = response
				.getSecondaryRequests();
		for (int i = 0; i < secondaryRequests.length; i++) {
			if (secondaryRequests[i].getName().compareTo(secondaryRequest) == 0) {
				return true;
			}
		}
		return false;
	}

	private CognosClient client;

	private boolean useEcho = true;

	protected ParameterValue[] _convertParameterValues(String params) {
		// 设置参数,多个参数用|线分割
		// 参数中有中文,则应先转成UTF-8
		String paramString = params;
		ParameterValue[] parameters = null;
		if (null != params) {
			try {
				paramString = new String(params.getBytes("UTF-8"), "UTF-8");
			} catch (UnsupportedEncodingException e) {
				log.error("resolve parameter failed: " + params);
			}

			String pm[] = paramString.split("\\|");
			parameters = new ParameterValue[pm.length];
			if (pm.length > 0) {
				for (int i = 0; i < pm.length; i++) {
					String[] tempParameter = pm[i].split("=");
					if (tempParameter.length > 1) {
						SimpleParmValueItem item = new SimpleParmValueItem();
						item.setUse(tempParameter[1]);
						item.setDisplay(tempParameter[1]);
						item.setInclusive(true);
						ParmValueItem[] pvi = new ParmValueItem[1];
						pvi[0] = item;
						parameters[i] = new ParameterValue();
						parameters[i].setName(tempParameter[0]);
						parameters[i].setValue(pvi);
					}
				}
			}
		} else {
			parameters = new ParameterValue[0];
		}
		return parameters;
	}

	protected Option[] _defaultRunOptions(String saveType) {
		if (null == saveType) {
			saveType = "XML";
		}
		// Set up the report parameters.
		// ParameterValue parameters[] = new ParameterValue[] {};
		Option[] runOptions = null;

		RunOptionBoolean saveOutput = new RunOptionBoolean();
		saveOutput.setName(RunOptionEnum.saveOutput);
		saveOutput.setValue(false);

		// TODO: Output format should be specified on the command-line
		RunOptionStringArray outputFormat = new RunOptionStringArray();
		outputFormat.setName(RunOptionEnum.outputFormat);
		outputFormat.setValue(new String[] { saveType });
		if(saveType.equals("MHT")) {
			outputFormat.setValue(new String[] { "HTML" });
		}

		RunOptionOutputEncapsulation outputEncapsulation = new RunOptionOutputEncapsulation();
		outputEncapsulation.setName(RunOptionEnum.outputEncapsulation);
		outputEncapsulation.setValue(OutputEncapsulationEnum.none);

		AsynchOptionInt primaryWait = new AsynchOptionInt();
		primaryWait.setName(AsynchOptionEnum.primaryWaitThreshold);
		primaryWait.setValue(0);

		AsynchOptionInt secondaryWait = new AsynchOptionInt();
		secondaryWait.setName(AsynchOptionEnum.secondaryWaitThreshold);
		secondaryWait.setValue(0);

		// 添加参数数组
		RunOptionBoolean prompt = new RunOptionBoolean();
		prompt.setName(RunOptionEnum.prompt);
		prompt.setValue(false);

		runOptions = new Option[] { saveOutput, outputFormat,
				outputEncapsulation, primaryWait, secondaryWait, prompt };
		return runOptions;
	}

	final public String _replaceSubstring(String str, String pattern,
			String replace) {
		int strLen = str.length();
		int patternLen = pattern.length();
		int start = 0, end = 0;
		StringBuffer result = new StringBuffer(strLen);
		char[] chars = new char[strLen];

		while ((end = str.indexOf(pattern, start)) >= 0) {
			str.getChars(start, end, chars, 0);
			result.append(chars, 0, end - start).append(replace);
			start = end + patternLen;
		}

		str.getChars(start, strLen, chars, 0);
		result.append(chars, 0, strLen - start);

		return result.toString();
	}

	public CognosClient getClient() {
		return client;
	}

	public boolean isUseEcho() {
		return useEcho;
	}

	final public void loadReport(ContentManagerServiceStub cmStub,
			ReportServiceStub repStub, String path, String params, String saveAs) {
		try {
			boolean run_result = this.runReport(cmStub, repStub, path, params,
					saveAs, null);
			if (!run_result) {
				log.info("generate report [" + path + "] failed");
			}
		} catch (Exception ex) {
			log.error(ex.getMessage(), ex);
		}
	}

	protected boolean outputIsReady(AsynchReply response) {
		for (int i = 0; i < response.getDetails().length; i++) {
			if ((response.getDetails()[i] instanceof AsynchDetailReportStatus)
					&& (((AsynchDetailReportStatus) response.getDetails()[i])
							.getStatus() == AsynchDetailReportStatusEnum.responseReady)
					&& (hasSecondaryRequest(response, "getOutput"))) {
				return true;
			}
		}
		return false;
	}

	final public String queryReportSpec(String path) throws RemoteException {
		// String from = "UTF-8";
		// String to = "GB18030"; // TODO
		String spec = null;
		ReportServiceStub repStub = (ReportServiceStub) this.getClient()
				.getService("Report", true, "");
		AsynchReply response = repStub.query(new SearchPathSingleObject(path),
				new ParameterValue[] {}, new Option[] {});
		if (!response.getStatus().equals(
				AsynchReplyStatusEnum.conversationComplete)) {
			while (!response.getStatus().equals(
					AsynchReplyStatusEnum.conversationComplete)) {
				response = repStub.wait(response.getPrimaryRequest(),
						new ParameterValue[] {}, new Option[] {});
			}

		}
		if (null != response) {
			boolean foundSpec = false;
			AsynchDetail[] ads = response.getDetails();
			for (int x = 0; x < ads.length && !foundSpec; x++) {
				if (ads[x] instanceof AsynchDetailReportObject) {
					AsynchDetailReportObject adro = ((AsynchDetailReportObject) ads[x]);
					foundSpec = true;
					AuthoredReport report = adro.getReport();
					spec = report.getSpecification().getValue();
				}
			}

		}

		return spec;
	}

	final public String executeReportSpec(String specXml, String params,
			String saveType) {
		String respXml = null;
		if (null == saveType) {
			saveType = "XML";
		}
		ContentManagerServiceStub cmStub = (ContentManagerServiceStub) client
				.getService("ContentManager");
		ReportServiceStub repStub = (ReportServiceStub) client
				.getService("Report");
		try {
			// options
			Option[] runOptions = this._defaultRunOptions(saveType);
			// parameters
			ParameterValue[] parameters = this._convertParameterValues(params);
			// spec
			Specification spec = new Specification();
			spec.set_value(specXml);
			ReportServiceReportSpecification rptSpec = new ReportServiceReportSpecification();
			rptSpec.setValue(spec);
			AsynchDetailReportOutput reportOutput = this.runReport(rptSpec,
					parameters, runOptions, null, repStub, cmStub);

			if (null != reportOutput) {
				if ("XML".equals(saveType)) {
					String[] data = reportOutput.getOutputPages();
					StringBuffer sb = new StringBuffer();
					for (int idx = 0; idx < data.length; idx++) {
						String str = new String(data[idx].getBytes());
						sb.append(str);
					}
					respXml = sb.toString();
				} else {
					this.saveAsHTML(reportOutput, cmStub, null);
				}
			}
		} catch (AxisFault ex) {
			log.error("load spec error: ", ex);
		} catch (RemoteException ex) {
			log.error("load spec error: ", ex);
		} catch (Exception ex) {
			log.error("load spec error: ", ex);
		}
		return respXml;
	}

	public String replaceLocalGraphicsInOutput(
			AsynchDetailReportOutput reportOutput) throws IOException {
		// this section deals with executing reports with charts or graphics.
		// the img tag contains credentials that are not valid when the report
		// is not run through report or query studio therefore we must extract
		// the img from content mgr and then save it locally, then replace the
		// img tag returned from the server with a path to the local graphic.
		// TODO Only the first graphic is handled. For reports with multiple
		// graphics, a for loop to process all of them would be appropriate.
		CognosClient client = this.getClient();
		BaseClass bcGraphic[];

		try {

			String graphicSearchPath = reportOutput.getOutputObjects()[0]
					.getSearchPath().getValue();
			bcGraphic = client.query(graphicSearchPath,
					new PropEnum[] { PropEnum.searchPath }, new Sort[] {},
					new QueryOptions(), null);
			Output out = null;
			if ((bcGraphic.length > 0) && (bcGraphic[0] instanceof Output)) {
				out = (Output) bcGraphic[0];
				Graphic g =

				(Graphic) client.query(out.getSearchPath().getValue()
						+ "/graphic", new PropEnum[] { PropEnum.searchPath,
						PropEnum.data, PropEnum.dataType }, new Sort[] {},
						new QueryOptions(), null)[0];

				String graphicFile = System.getProperty("java.io.tmpdir")
						+ System.getProperty("file.separator")
						+ "graphicToDisplay.png";

				// save graphic locally
				File gFile = new File(graphicFile);
				FileOutputStream fos = new FileOutputStream(gFile);
				fos.write(g.getData().getValue());
				fos.flush();
				fos.close();

				// return the HTML output, search&replace img tag with local
				// image.
				String[] pages = reportOutput.getOutputPages();
				String html = pages[0].toString();

				String start = null;
				String end = null;
				int index = 0;
				index = html.indexOf("<img", 0);
				start = html.substring(0, index);
				end = html.substring(html.indexOf(">", index) + 1);
				html = start + "<img src='graphicToDisplay.png'>" + end;

				return html;
			}

		} catch (RemoteException ex) {
			log.error("replaceLocalGraphicsInOutput errors: ", ex);
		} catch (Exception ex) {
			log.error("replaceLocalGraphicsInOutput errors: ", ex);
		}

		return "";
	}

	protected AsynchDetailReportOutput runReport(Object report,
			ParameterValue[] parameters, Option[] runOptions, String saveAs,
			ReportServiceStub reportStub, ContentManagerServiceStub cmStub)
			throws Exception {
		// Now, run the report.
		AsynchReply res = null;
		// report output
		AsynchDetailReportOutput reportOutput = null;

		try {
			if (!(report instanceof AsynchSpecification)) {
				String reportPath = (String) report;
				if (log.isDebugEnabled() && useEcho) {
					log.debug("report_path: " + reportPath);
				}
				// com.cognos.developer.schemas.bibus._3.ReportServiceStub
				// com.cognos.developer.schemas.bibus._3.InteractiveReport
				reportStub.setTimeout(20*60*1000);	//delay timeout,default timout is 1min
				try {
					res = reportStub.run(new SearchPathSingleObject(reportPath),
							parameters, runOptions);
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else if (report instanceof AsynchSpecification) {
				AsynchSpecification reportSpec = (AsynchSpecification) report;
				if (log.isDebugEnabled() && useEcho) {
					log.debug("report_spec: "
							+ reportSpec.getValue().get_value());
				}
				res = reportStub.runSpecification((AsynchSpecification) report,
						parameters, runOptions);
			} else {
				return null;
			}

			if (log.isDebugEnabled() && useEcho) {
				log.debug("report_job: done");
			}
			if (null != res
					&& res.getStatus() == AsynchReplyStatusEnum.complete) {
				for (int i = 0; i < res.getDetails().length; i++) {
					if (res.getDetails()[i] instanceof AsynchDetailReportOutput) {
						reportOutput = (AsynchDetailReportOutput) res
								.getDetails()[i];
						break;
					}
				}
			}

			/*
			 * TODO boolean execError = false; if
			 * (!res.getStatus().equals(AsynchReplyStatusEnum.complete) &&
			 * !res.getStatus().equals(
			 * AsynchReplyStatusEnum.conversationComplete)) { while
			 * (!res.getStatus().equals(AsynchReplyStatusEnum.complete) &&
			 * !res.getStatus().equals(
			 * AsynchReplyStatusEnum.conversationComplete)) { if
			 * (!hasSecondaryRequest(res, "wait")) { execError = true; break; }
			 * 
			 * res = reportStub.wait(res.getPrimaryRequest(), new
			 * ParameterValue[] {}, new Option[] {}); }
			 * 
			 * // After calling wait() it is necessary to check to make sure //
			 * the output is ready before retrieving it if (!execError &&
			 * outputIsReady(res)) { res = reportStub.getOutput(
			 * res.getPrimaryRequest(), new ParameterValue[] {}, new Option[]
			 * {}); } else { execError = true; } System.out.println("res: " +
			 * res); System.out.println("execError: " + execError);
			 * if(!execError) { for (int i = 0; i < res.getDetails().length;
			 * i++) { if (res.getDetails()[i] instanceof
			 * AsynchDetailReportOutput) { reportOutput =
			 * (AsynchDetailReportOutput)res.getDetails()[i]; break; } } } }
			 */
		} finally {
			if (null != res) {
				res = null;
			}
		}

		return reportOutput;
	}

	/**
	 * 
	 * @param cmStub
	 * @param repStub
	 * @param path    搜索路径
	 * @param params   时间字符串
	 * @param saveAs  报表保存路径
	 * @param props
	 * @return
	 */
	synchronized public boolean runReport(ContentManagerServiceStub cmStub,
			ReportServiceStub repStub, String path, String params,
			String saveAs, Properties props) {
		boolean run_result = false;
		String saveType = "HTML";
		if (null != saveAs) {
			// File saveFile = new File(saveAs);
			// if (saveFile.exists()) {
			// // TODO jhsea3do
			// }
			if (saveAs.toLowerCase().endsWith(".pdf")) {
				saveType = "PDF";
			} else if (saveAs.toLowerCase().endsWith(".csv")) {
				saveType = "CSV";
			} else if (saveAs.toLowerCase().endsWith(".xls")) {
				saveType = "XLWA";//singleXLS
			} else if (saveAs.toLowerCase().endsWith(".xlwa")) {
				saveType = "XLWA";
			} else if (saveAs.toLowerCase().endsWith(".xlsx")) {
				saveType = "spreadsheetML";
			} else if (saveAs.toLowerCase().endsWith(".xml")) {
				saveType = "XML";
			} else if (saveAs.toLowerCase().endsWith(".mht")) {
				saveType = "MHT";
			} else if (saveAs.toLowerCase().endsWith(".htmlf")) {
				saveType = "HTMLFragment";
			} else if (saveAs.toLowerCase().endsWith(".sxls")) {
				saveType = "singleXLS";
			}
			if (this.isUseEcho()) {
				log.info("save type: " + saveType);
			}
		}
		if (null == cmStub) {
			cmStub = (ContentManagerServiceStub) client
					.getService("ContentManager");
		}
		if (null == repStub) {
			repStub = (ReportServiceStub) client.getService("Report", true, "");
		}
		if (null == repStub || null == cmStub) {
			String errorMessage = "Can not initial ContentManagerService or ReportService instance";
			if (null != props) {
				props.setProperty("run.errors", errorMessage);
			}
			log.error(errorMessage);
			return run_result;
		}

		try {
			String reportPath = path;
			// options
			Option[] runOptions = this._defaultRunOptions(saveType);
			// parameters
			ParameterValue[] parameters = this._convertParameterValues(params);
			AsynchDetailReportOutput reportOutput = this.runReport(reportPath,
					parameters, runOptions, saveAs, repStub, cmStub);
			if (null != reportOutput) {
				if (saveType.equals("PDF")) {
					this.saveAsPDF(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("CSV")) {
					this.saveAsCSV(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("XML")) {
					this.saveAsXML(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("XLS")) {
					this.saveAsXLS(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("spreadsheetML")) {
					this.saveAsXLSX(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("XLWA")) {
					this.saveAsXLWA(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("MHT")) {
					this.saveAsMHT(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("HTMLFragment")) {
					this.saveAsHTMLFragment(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("singleXLS")) {
					this.saveAsSingleXLS(reportOutput, cmStub, saveAs);
				} else {
					this.saveAsHTML(reportOutput, cmStub, saveAs);
				}
			}
			run_result = true;
		} catch (AxisFault ex) {
			if (null != props) {
				props.setProperty("run.errors", "cognos soap error: "
						+ CognosHelper.parseErrorDetails(ex));
			}
			log.error("load report error: "+ ex.getFaultString());
			log.error("detail error: ",ex);
		} catch (RemoteException ex) {
			if (null != props) {
				props.setProperty("run.errors",
						"load soap error: " + ex.getMessage());
			}
			log.error("load report error: ", ex);
		} catch (Exception ex) {
			if (null != props) {
				props.setProperty("run.errors",
						"load report error: " + ex.getMessage());
			}
			log.error("load report error: ", ex);
		}
		return run_result;
	}

	synchronized public boolean runSpec(ContentManagerServiceStub cmStub,
			ReportServiceStub repStub, String specXml, String params,
			String saveAs, Properties props) {
		boolean run_result = false;
		String saveType = "HTML";
		if (null != saveAs) {
			if (saveAs.toLowerCase().endsWith(".pdf")) {
				saveType = "PDF";
			} else if (saveAs.toLowerCase().endsWith(".csv")) {
				saveType = "CSV";
			} else if (saveAs.toLowerCase().endsWith(".xls")) {
				saveType = "XLS";
			} else if (saveAs.toLowerCase().endsWith(".xlwa")) {
				saveType = "XLWA";
			} else if (saveAs.toLowerCase().endsWith(".xlsx")) {
				saveType = "spreadsheetML";
			} else if (saveAs.toLowerCase().endsWith(".xml")) {
				saveType = "XML";
			} else if (saveAs.toLowerCase().endsWith(".mht")) {
				saveType = "MHT";
			} else if (saveAs.toLowerCase().endsWith(".htmlf")) {
				saveType = "HTMLFragment";
			} else if (saveAs.toLowerCase().endsWith(".sxls")) {
				saveType = "singleXLS";
			}
			if (this.isUseEcho()) {
				log.info("save type: " + saveType);
			}
		}
		if (null == cmStub) {
			cmStub = (ContentManagerServiceStub) client
					.getService("ContentManager");
		}
		if (null == repStub) {
			repStub = (ReportServiceStub) client.getService("Report", true, "");
		}
		if (null == repStub || null == cmStub) {
			String errorMessage = "Can not initial ContentManagerService or ReportService instance";
			if (null != props) {
				props.setProperty("run.errors", errorMessage);
			}
			log.error(errorMessage);
			return run_result;
		}
		try {
			// options
			Option[] runOptions = this._defaultRunOptions(saveType);
			// parameters
			ParameterValue[] parameters = this._convertParameterValues(params);
			// spec
			Specification spec = new Specification();
			spec.set_value(specXml);
			ReportServiceReportSpecification rptSpec = new ReportServiceReportSpecification();
			rptSpec.setValue(spec);
			AsynchDetailReportOutput reportOutput = this.runReport(rptSpec,
					parameters, runOptions, saveAs, repStub, cmStub);
			if (null != reportOutput) {
				if (saveType.equals("PDF")) {
					this.saveAsPDF(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("CSV")) {
					this.saveAsCSV(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("XML")) {
					this.saveAsXML(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("XLS")) {
					this.saveAsXLS(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("spreadsheetML")) {
					this.saveAsXLSX(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("XLWA")) {
					this.saveAsXLWA(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("MHT")) {
					this.saveAsMHT(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("HTMLFragment")) {
					this.saveAsHTMLFragment(reportOutput, cmStub, saveAs);
				} else if (saveType.equals("singleXLS")) {
					this.saveAsSingleXLS(reportOutput, cmStub, saveAs);
				} else {
					this.saveAsHTML(reportOutput, cmStub, saveAs);
				}
			}
			run_result = true;
		} catch (AxisFault ex) {
			if (null != props) {
				props.setProperty("run.errors", "cognos soap error: "
						+ CognosHelper.parseErrorDetails(ex));
			}
			log.error("load report error: ", ex);
		} catch (RemoteException ex) {
			if (null != props) {
				props.setProperty("run.errors",
						"load soap error: " + ex.getMessage());
			}
			log.error("load report error: ", ex);
		} catch (Exception ex) {
			if (null != props) {
				props.setProperty("run.errors",
						"load report error: " + ex.getMessage());
			}
			log.error("load report error: ", ex);
		}
		return run_result;
	}

	/**
	 * Save As CSV
	 * 
	 * @param reportOutput
	 * @param cmPort
	 * @param saveAs
	 * @throws java.io.IOException
	 */
	final public void saveAsAny(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs, String extension)
			throws IOException {
		String savePath = System.getProperty("java.io.tmpdir",
				"c:" + System.getProperty("file.separator") + "temp");
		// String saveName = "c8temp.html";
		String saveName = "c8temp" + System.currentTimeMillis() + extension;
		File saveFile = null;
		if (null != saveAs) {
			saveFile = new File(saveAs);
			savePath = saveFile.getParent() + File.separator;
			saveName = saveFile.getName();
		} else {
			saveFile = new File(savePath + saveName);
		}
		// create the report output directory if not exist
		File dir = new File(savePath);
		if (!dir.exists()) {
			dir.mkdirs();
		}
		String[] data = reportOutput.getOutputPages();
		FileOutputStream fs = new FileOutputStream(saveFile);
		// URIs in the output are relative on the server; we need to
		// make them absolute so they reference the server properly.
		byte binaryOutput[] = null;
		for (int idx = 0; idx < data.length; idx++) {
			if (extension.equals(".xml") || extension.equals(".xlwa")
					|| extension.equals(".xls")) {
				fs.write(data[idx].getBytes());
			} else { // csv, pdf
				binaryOutput = org.apache.axis.encoding.Base64
						.decode(data[idx]);
				if (binaryOutput != null)
					fs.write(binaryOutput);
			}
		}
		fs.flush();
		fs.close();
		if (this.isUseEcho()) {
			log.info("Writing report output to " + saveFile + "...");
		}
	}

	final public void saveAsciiOutput(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs, String extension)
			throws IOException {
		String savePath = System.getProperty("java.io.tmpdir",
				"c:" + System.getProperty("file.separator") + "temp");
		// String saveName = "c8temp.html";
		String saveName = "c8temp" + System.currentTimeMillis() + extension;
		File saveFile = null;
		if (null != saveAs) {
			saveFile = new File(saveAs);
			savePath = saveFile.getParent() + File.separator;
			saveName = saveFile.getName();
		} else {
			saveFile = new File(savePath + saveName);
		}
		// create the report output directory if not exist
		File dir = new File(savePath);
		if (!dir.exists()) {
			dir.mkdirs();
		}
		String textOutput = "";

		if (reportOutput.getOutputObjects().length > 0) {
			textOutput = replaceLocalGraphicsInOutput(reportOutput);
		} else {
			// text based output is split into pages -- return the current page
			String[] pages = reportOutput.getOutputPages();
			textOutput = pages[0].toString();
		}
		// write the updated html output to a file
		FileOutputStream fos = new FileOutputStream(saveFile);

		fos.write(textOutput.getBytes());
		// fos.write(textOutput.getBytes("UTF-8"));
		fos.flush();
		fos.close();

		if (this.isUseEcho()) {
			log.info("Writing report output to " + saveFile + "...");
		}

	}
	
	final public void saveAsciiOutput2(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs, String extension)
			throws IOException {
		String savePath = System.getProperty("java.io.tmpdir",
				"c:" + System.getProperty("file.separator") + "temp");
		// String saveName = "c8temp.html";
		String saveName = "c8temp" + System.currentTimeMillis() + extension;
		File saveFile = null;
		if (null != saveAs) {
			saveFile = new File(saveAs);
			savePath = saveFile.getParent() + File.separator;
			saveName = saveFile.getName();
		} else {
			saveFile = new File(savePath + saveName);
		}
		// create the report output directory if not exist
		File dir = new File(savePath);
		if (!dir.exists()) {
			dir.mkdirs();
		}
		String textOutput = "";

		if (reportOutput.getOutputObjects().length > 0) {
			textOutput = reportOutput.getOutputPages()[0];
		} else {
			// text based output is split into pages -- return the current page
			String[] pages = reportOutput.getOutputPages();
			textOutput = pages[0];
		}
		// write the updated html output to a file
		FileOutputStream fos = new FileOutputStream(saveFile);
		// fos.write(textOutput.getBytes());
		// log.info(textOutput);
		fos.write(new String(textOutput.getBytes("ISO-8859-1"), "UTF-8").getBytes("UTF-8"));
		fos.flush();
		fos.close();

		if (this.isUseEcho()) {
			log.info("Writing report output to " + saveFile + "...");
		}

	}

	/**
	 * Save As CSV
	 * 
	 * @param reportOutput
	 * @param cmPort
	 * @param saveAs
	 * @throws java.io.IOException
	 */
	final public void saveAsCSV(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs) throws IOException {
		saveBinaryOutput(reportOutput, cmStub, saveAs, ".csv");
	}

	/**
	 * Save As HTML
	 * 
	 * @param reportOutput
	 * @param cmPort
	 * @param saveAs
	 * @throws java.io.IOException
	 */
	final public void saveAsHTML(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs) throws IOException {
		// FIXME
		String basic_url = this.getClient().getGateway();
		if (null == basic_url) {
			basic_url = this.getClient().getDispatch();
		}
		if (basic_url.indexOf("/p2pd") > -1) {
			basic_url = basic_url.substring(0, basic_url.indexOf("/p2pd"))
					+ "/p2pd/";
		} else if (basic_url.indexOf("/cgi-bin") > -1) {
			basic_url = basic_url.substring(0, basic_url.indexOf("/cgi-bin"))
					+ "/";
		}
		log.info("save html use basic_url: " + basic_url);
		String savePath = System.getProperty("java.io.tmpdir");
		// String saveName = "c8temp.html";
		String saveName = "c8temp" + System.currentTimeMillis() + ".html";
		File saveFile = null;

		if (null != saveAs) {
			saveFile = new File(saveAs);
			savePath = saveFile.getParent() + File.separator;
			saveName = saveFile.getName();
		} else {
			saveFile = new File(savePath + saveName);
		}
		// create the report output directory if not exist
		File dir = new File(savePath);
		if (!dir.exists()) {
			dir.mkdirs();
		}
		String[] data = reportOutput.getOutputPages();
		FileOutputStream fs = new FileOutputStream(saveFile);
		// URIs in the output are relative on the server; we need to
		// make them absolute so they reference the server properly.
		for (int idx = 0; idx < data.length; idx++) {
			String html = data[idx];
			String fix = this._replaceSubstring(html, "../skins/../", "../");
			fix = this._replaceSubstring(fix, "../", basic_url);
			fs.write(fix.getBytes("UTF-8"));
		}
		fs.flush();
		fs.close();
		log.info("Writing report output to " + saveFile + "...");
	}

	/**
	 * Save As HTML
	 * 
	 * @param reportOutput
	 * @param cmPort
	 * @param saveAs
	 * @throws java.io.IOException
	 */
	final public void saveAsHTML2(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs) throws IOException {
		saveAsciiOutput(reportOutput, cmStub, saveAs, ".html");
	}

	/**
	 * Save As HTMLFragment
	 * 
	 * @param reportOutput
	 * @param cmPort
	 * @param saveAs
	 * @throws java.io.IOException
	 */
	final public void saveAsHTMLFragment(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs) throws IOException {
		saveAsciiOutput(reportOutput, cmStub, saveAs, ".htmlf");
	}

	/**
	 * Save As MHT
	 * 
	 * @param reportOutput
	 * @param cmPort
	 * @param saveAs
	 * @throws java.io.IOException
	 */
	final public void saveAsMHT(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs) throws IOException {
		saveAsciiOutput2(reportOutput, cmStub, saveAs, ".mht");
	}

	/**
	 * Save As PDF
	 * 
	 * @param reportOutput
	 * @param cmPort
	 * @param saveAs
	 * @throws java.io.IOException
	 */
	final public void saveAsPDF(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs) throws IOException {
		saveBinaryOutput(reportOutput, cmStub, saveAs, ".pdf");
	}

	/**
	 * Save As SingleXLS
	 * 
	 * @param reportOutput
	 * @param cmPort
	 * @param saveAs
	 * @throws java.io.IOException
	 */
	final public void saveAsSingleXLS(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs) throws IOException {
		saveBinaryOutput(reportOutput, cmStub, saveAs, ".sxls");
	}

	/**
	 * Save As XLS
	 * 
	 * @param reportOutput
	 * @param cmPort
	 * @param saveAs
	 * @throws java.io.IOException
	 */
	final public void saveAsXLS(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs) throws IOException {
		saveBinaryOutput(reportOutput, cmStub, saveAs, ".xls");
	}

	/**
	 * Save As XLSX
	 * 
	 * @param reportOutput
	 * @param cmPort
	 * @param saveAs
	 * @throws java.io.IOException
	 */
	final public void saveAsXLSX(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs) throws IOException {
		saveBinaryOutput(reportOutput, cmStub, saveAs, ".xlsx");
	}

	/**
	 * Save As XLWA
	 * 
	 * @param reportOutput
	 * @param cmPort
	 * @param saveAs
	 * @throws java.io.IOException
	 */
	final public void saveAsXLWA(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs) throws IOException {
		saveBinaryOutput(reportOutput, cmStub, saveAs, ".xlwa");
	}

	/**
	 * Save As XML
	 * 
	 * @param reportOutput
	 * @param cmPort
	 * @param saveAs
	 * @throws java.io.IOException
	 */
	final public void saveAsXML(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs) throws IOException {
		saveAsciiOutput(reportOutput, cmStub, saveAs, ".xml");
	}

	final public void saveBinaryOutput(AsynchDetailReportOutput reportOutput,
			ContentManagerServiceStub cmStub, String saveAs, String extension)
			throws IOException {
		String savePath = System.getProperty("java.io.tmpdir",
				"c:" + System.getProperty("file.separator") + "temp");
		// String saveName = "c8temp.html";
		String saveName = "c10temp" + System.currentTimeMillis() + extension;
		File saveFile = null;
		if (null != saveAs) {
			saveFile = new File(saveAs);
			savePath = saveFile.getParent() + File.separator;
			saveName = saveFile.getName();
		} else {
			saveFile = new File(savePath + saveName);
		}
		// create the report output directory if not exist
		File dir = new File(savePath);
		if (!dir.exists()) {
			dir.mkdirs();
		}
		String[] data = reportOutput.getOutputPages();
		FileOutputStream fs = new FileOutputStream(saveFile);
		// URIs in the output are relative on the server; we need to
		// make them absolute so they reference the server properly.
		byte binaryOutput[] = null;
		for (int idx = 0; idx < data.length; idx++) {
			if (extension.equals(".xml") || extension.equals(".xlwa")
					|| extension.equals(".xls")) {
				fs.write(data[idx].getBytes());
			} else { // csv, pdf
				binaryOutput =Base64
						.decode(data[idx]);
				if (binaryOutput != null)
					fs.write(binaryOutput);
			}
		}
		fs.flush();
		fs.close();
		if (this.isUseEcho()) {
			log.info("Writing report output to " + saveFile + "...");
		}
	}

	final private AsynchReply getParameters(ReportServiceStub repStub,
			Object report) throws java.rmi.RemoteException {
		AsynchReply response;
		if (report instanceof AsynchSpecification
				|| report instanceof Specification) {
			response = ((ReportServiceStub) repStub)
					.getParametersSpecification((AsynchSpecification) report,
							new ParameterValue[] {}, new Option[] {});
		} else {
			response = ((ReportServiceStub) repStub).getParameters(
					new SearchPathSingleObject(report.toString()),
					new ParameterValue[] {}, new Option[] {});
		}
		if (!response.getStatus().equals(
				AsynchReplyStatusEnum.conversationComplete)) {
			while (!response.getStatus().equals(
					AsynchReplyStatusEnum.conversationComplete)) {
				response = ((ReportServiceStub) repStub).wait(
						response.getPrimaryRequest(), new ParameterValue[] {},
						new Option[] {});
			}

		}
		return response;
	}

	final public BaseParameter[] getReportParameters(ReportServiceStub repStub,
			String path) throws java.rmi.RemoteException {

		BaseParameter params[] = new Parameter[] {};
		if (null == repStub) {
			repStub = (ReportServiceStub) client.getService("Report", true, "");
		}

		AsynchReply response = this.getParameters(repStub, path);
		for (int i = 0; i < response.getDetails().length; i++) {
			if (response.getDetails()[i] instanceof AsynchDetailParameters)

			{
				params = ((AsynchDetailParameters) response.getDetails()[i])
						.getParameters();
			}
		}

		return params;

	}

	final public BaseParameter[] getSpecParameters(ReportServiceStub repStub,
			String specXml) throws java.rmi.RemoteException {

		BaseParameter params[] = new Parameter[] {};
		if (null == repStub) {
			repStub = (ReportServiceStub) client.getService("Report", true, "");
		}

		Specification spec = new Specification();
		spec.set_value(specXml);
		ReportServiceReportSpecification rptSpec = new ReportServiceReportSpecification();
		rptSpec.setValue(spec);
		AsynchReply response = this.getParameters(repStub, rptSpec);
		for (int i = 0; i < response.getDetails().length; i++) {
			if (response.getDetails()[i] instanceof AsynchDetailParameters)

			{
				params = ((AsynchDetailParameters) response.getDetails()[i])
						.getParameters();
			}
		}

		return params;

	}

	final public String buildQuerySpec(Document document, Node query,
			String useName, String dispName) throws XPathExpressionException,
			TransformerException, ParserConfigurationException {
		DocumentBuilder builder = XML_DBF.newDocumentBuilder();
		Document doc = builder.newDocument();
		XPathExpression xpRpt = XML_XPF.newXPath().compile("/report");
		XPathExpression xpMdl = XML_XPF.newXPath().compile("/report/modelPath");
		Element elemRpt = (Element) xpRpt.evaluate(document,
				XPathConstants.NODE);
		NamedNodeMap attrRpts = elemRpt.getAttributes();
		Element elemMdl = (Element) xpMdl.evaluate(document,
				XPathConstants.NODE);
		NamedNodeMap attrMdls = elemMdl.getAttributes();
		Element eReport = (Element) doc.importNode(elemRpt, false);
		Element eQuery = doc.createElement("queries");
		eReport.appendChild(doc.importNode(elemMdl, true));
		eQuery.appendChild(doc.importNode(query, true));
		eReport.appendChild(eQuery);

		Element elemContents = doc.createElement("contents");
		Element elemLst = doc.createElement("list");
		elemLst.setAttribute("refQuery", ((Element) query).getAttribute("name"));
		elemLst.setAttribute("horizontalPagination", "true");
		elemLst.setAttribute("name", "List1");
		Element elemListColumns = doc.createElement("listColumns");
		String[] cols = new String[] { useName, dispName };
		for (int i = 0; i < cols.length; i++) {
			Element elemListColumn = doc.createElement("listColumn");
			Element elemListColumnTitle = doc.createElement("listColumnTitle");
			Element elemListColumnBody = doc.createElement("listColumnBody");
			Element elemDataItemLabel = doc.createElement("dataItemLabel");
			Element elemDataItemValue = doc.createElement("dataItemValue");
			Element eDataSourceLabel = doc.createElement("dataSource");
			Element eTextItemLabel = doc.createElement("textItem");
			Element eContentsLabel = doc.createElement("contents");
			Element eDataSourceValue = doc.createElement("dataSource");
			Element eTextItemValue = doc.createElement("textItem");
			Element eContentsValue = doc.createElement("contents");
			elemDataItemValue.setAttribute("refDataItem", cols[i]);
			elemDataItemLabel.setAttribute("refDataItem", cols[i]);
			// elemDataItemValue.setAttribute("refDataItem", useName);
			// elemDataItemLabel.setAttribute("refDataItem", dispName);
			eDataSourceValue.appendChild(elemDataItemValue);
			eTextItemValue.appendChild(eDataSourceValue);
			eContentsValue.appendChild(eTextItemValue);
			eDataSourceLabel.appendChild(elemDataItemLabel);
			eTextItemLabel.appendChild(eDataSourceLabel);
			eContentsLabel.appendChild(eTextItemLabel);
			elemListColumnTitle.appendChild(eContentsLabel);
			elemListColumnBody.appendChild(eContentsValue);

			elemListColumn.appendChild(elemListColumnTitle);
			elemListColumn.appendChild(elemListColumnBody);
			elemListColumns.appendChild(elemListColumn);
		}
		elemLst.appendChild(elemListColumns);
		elemContents.appendChild(elemLst);

		Element elemLayouts = doc.createElement("layouts");
		Element elemLayout = doc.createElement("layout");
		Element elemReportPages = doc.createElement("reportPages");
		Element elemPage = doc.createElement("page");
		Element elemPageBody = doc.createElement("pageBody");
		elemPage.setAttribute("name", "Page1");
		elemPageBody.appendChild(elemContents);
		elemPage.appendChild(elemPageBody);
		elemReportPages.appendChild(elemPage);
		elemLayout.appendChild(elemReportPages);
		elemLayouts.appendChild(elemLayout);
		eReport.appendChild(elemLayouts);

		doc.appendChild(eReport);

		StringWriter sw = new StringWriter();
		Transformer tf = XML_TFF.newTransformer();
		tf.transform(new DOMSource(doc), new StreamResult(sw));
		String specXml = sw.toString();
		return specXml;
	}

	final public Properties[] parseDataSet(String dataSetXml) {
		Properties[] array = null;
		try {
			Document document = this.getDocument(dataSetXml, null);
			NodeList metadataItems = (NodeList) XML_XPF.newXPath()
					.compile("/dataset/metadata/item")
					.evaluate(document, XPathConstants.NODESET);
			NodeList dataRows = (NodeList) XML_XPF.newXPath()
					.compile("/dataset/data/row")
					.evaluate(document, XPathConstants.NODESET);
			String[][] prototypes = null;
			if (null != metadataItems) {
				prototypes = new String[metadataItems.getLength()][2];
				for (int i = 0; i < metadataItems.getLength(); i++) {
					Element item = (Element) metadataItems.item(i);
					prototypes[i][0] = item.getAttribute("name");
					prototypes[i][1] = item.getAttribute("type");
				}

			}
			if (null != dataRows) {
				array = new Properties[dataRows.getLength()];
				for (int i = 0; i < dataRows.getLength(); i++) {
					Element row = (Element) dataRows.item(i);
					NodeList vals = row.getElementsByTagName("value");
					Properties props = new Properties();
					for (int a = 0; a < prototypes.length; a++) {
						props.put(prototypes[a][0], vals.item(a)
								.getTextContent());
					}
					array[i] = props;
				}

			}
		} catch (Exception ex) {
			log.error("Parse DataSet XML failed: " + ex.getMessage(), ex);
		}
		return array;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	final public Map queryReportParam(Document document, String name)
			throws XPathExpressionException, TransformerException,
			ParserConfigurationException {
		String expr = "//page//*[@parameter='" + name + "']";
		XPathExpression xpath = XML_XPF.newXPath().compile(expr);
		NodeList nl = (NodeList) xpath.evaluate(document,
				XPathConstants.NODESET);
		Element elem = null;
		for (int a = 0; a < nl.getLength(); a++) {
			Element node = (Element) nl.item(a);
			// selectValue, selectDate
			if (!"parameterContext".equals(node.getTagName())) {
				elem = node;
				break;
			}
		}
		Map param = new LinkedHashMap();
		if (null != elem) {
			Properties values = null;
			param.put("type", elem.getTagName());
			if (null != elem.getAttribute("required")) {
				param.put("required", elem.getAttribute("required"));
			} else {
				param.put("required", "false");
			}
			if (null != elem.getAttribute("multiSelect")) {
				param.put("multiSelect", elem.getAttribute("multiSelect"));
			} else {
				param.put("multiSelect", "false");
			}
			if (null != elem.getAttribute("refQuery")) {
				String queryName = elem.getAttribute("refQuery");
				String cascadeOn = null;
				if (elem.hasAttribute("cascadeOn")) {
					cascadeOn = elem.getAttribute("cascadeOn");
				}
				boolean useDetailFilters = false;
				XPathExpression xpUse = XML_XPF.newXPath().compile(
						expr + "/useItem");
				Element elemUse = (Element) xpUse.evaluate(elem,
						XPathConstants.NODE);
				XPathExpression xpDisp = XML_XPF.newXPath().compile(
						expr + "/useItem/displayItem");
				Element elemDisp = (Element) xpDisp.evaluate(elem,
						XPathConstants.NODE);
				String useName = elemUse.getAttribute("refDataItem");
				String dispName = elemDisp.getAttribute("refDataItem");

				XPathExpression elemQueryXpath = XML_XPF.newXPath().compile(
						"//queries/query[@name='" + queryName + "']");
				Element nlQuery = (Element) elemQueryXpath.evaluate(document,
						XPathConstants.NODE);
				String querySpec = buildQuerySpec(document, nlQuery, useName,
						dispName);
				XPathExpression elemQDFXpath = XML_XPF.newXPath().compile(
						"//queries/query[@name='" + queryName
								+ "']/detailFilters");
				Element nlQDF = (Element) elemQDFXpath.evaluate(document,
						XPathConstants.NODE);
				if (null != nlQDF) {
					useDetailFilters = true;
				}

				if (!useDetailFilters) {
					String queryDataSetXml = this.executeReportSpec(querySpec,
							"", null);
					// System.out.println(queryDataSetXml);
					Properties[] dataSet = this.parseDataSet(queryDataSetXml);
					values = new Properties();
					for (int s = 0; s < dataSet.length; s++) {
						Properties data = dataSet[s];
						values.setProperty(data.getProperty(dispName),
								data.getProperty(useName));
					}
					param.put("values", values);
				}
			}
			// if(null != elem.getAttribute("cascadeOn")) { }
			if ("selectValue".equals(elem.getTagName())) {
				values = new Properties();
				XPathExpression elemValsXpath = XML_XPF.newXPath().compile(
						expr + "/selectOptions/selectOption");
				NodeList nlVals = (NodeList) elemValsXpath.evaluate(elem,
						XPathConstants.NODESET);
				if (null != nlVals) {
					for (int a = 0; a < nlVals.getLength(); a++) {
						Element option = (Element) nlVals.item(a);
						String key = option.getAttribute("useValue");
						String val = option.getTextContent();
						values.setProperty(key, val);
					}
				}
				if (null == param.get("values")) {
					param.put("values", values);
				}
			}
			XPathExpression elemDefsXpath = XML_XPF.newXPath().compile(
					expr + "/defaultSelections/defaultSimpleSelection");
			NodeList nlDefs = (NodeList) elemDefsXpath.evaluate(elem,
					XPathConstants.NODESET);
			if (null != nlDefs) {
				StringBuffer sb = new StringBuffer();
				for (int a = 0; a < nlDefs.getLength(); a++) {
					String value = nlDefs.item(a).getTextContent();
					if (null != values) {
						value = values.getProperty(value);
					}
					if (sb.length() > 0) {
						sb.append(",");
					}
					if (null != value) {
						sb.append(value);
					}
				}
				param.put("value", sb);
			}
		}
		return param;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	final public Map queryReportParams(String specXml,
			BaseParameter[] parameters) throws UnsupportedEncodingException,
			SAXException, IOException, RemoteException,
			XPathExpressionException, TransformerException,
			ParserConfigurationException {
		if (null == parameters) {
			parameters = this.getSpecParameters(null, specXml);
		}
		if (null == parameters) {
			return new LinkedHashMap();
		}
		Map params = new LinkedHashMap(parameters.length);
		Document document = this.getDocument(specXml, null);
		for (int i = 0; i < parameters.length; i++) {
			String name = parameters[i].getName();
			params.put(name, queryReportParam(document, name));
		}
		return params;
	}

	private Document getDocument(String xml, String charset)
			throws UnsupportedEncodingException, SAXException, IOException {
		Document document = null;
		if (null == charset) {
			// charset = "ISO-8859-1";
			charset = "UTF-8";
		}
		try {
			DocumentBuilder builder = XML_DBF.newDocumentBuilder();
			document = builder.parse(new ByteArrayInputStream(xml
					.getBytes(charset)));
		} catch (Exception ex) {
			log.fatal("can not initial document builder of report plugin.");
			document = null;
		}
		return document;
	}

	public void setClient(CognosClient client) {
		this.client = client;
	}

	public void setUseEcho(boolean useEcho) {
		this.useEcho = useEcho;
	}

	static DocumentBuilderFactory XML_DBF = DocumentBuilderFactory
			.newInstance();

	static XPathFactory XML_XPF = XPathFactory.newInstance();

	static TransformerFactory XML_TFF = TransformerFactory.newInstance();
	
	
	
	//cognosopt
//	public void getRolePerFromCogObj(String obj_searchpath)
//	  {
//	    BaseClass[] results = new BaseClass[0];
//	    try {
//	      results = ((ContentManagerServiceStub)this.getClient().getService("ContentManagerService")).query(
//	        new SearchPathMultipleObject(obj_searchpath), 
//	        new PropEnum[] { PropEnum.searchPath, PropEnum.policies }, 
//	        new Sort[0], new QueryOptions());
//	    } catch (RemoteException remoteEx) {
//	      System.out.println("Caught Remote Exception:\n");
//	      remoteEx.printStackTrace();
//	    }
//
//	    for (int i = 0; i < results[0].getPolicies().getValue().length; ++i) {
//	      Policy pol = results[0].getPolicies().getValue()[i];
//	      getUserFromRole(pol.getSecurityObject().getSearchPath().getValue());
//	    }
//	  }
//
//	  public void getUserFromRole(String rolesearchpath) {
//	    PropEnum[] props = { PropEnum.searchPath, PropEnum.defaultName, 
//	      PropEnum.members };
//	    if (this.getClient() != null) {
//	      Sort[] sortArray = { new Sort() };
//	      try {
//	        BaseClass[] bc = ((ContentManagerServiceStub)this.getClient().getService("ContentManagerService")).query(
//	          new SearchPathMultipleObject(rolesearchpath), props, 
//	          sortArray, new QueryOptions());
//	        if (bc == null)
////	          logger.info("\n\nError occurred in function viewAll.");
//	        if (bc.length <= 0) {
////	          logger.info("There are currently no user.");
//	        }
//	        for (int i = 0; i < bc.length; ++i) {
//	          String objectName = bc[i].getDefaultName().getValue();
//	          String objectPath = bc[i].getSearchPath().getValue();
//
//	          BaseClass[] bcchildren = new BaseClass[1];
//
//	          if (bc[i] instanceof Role) {
//	            bcchildren = ((Role)bc[i]).getMembers().getValue();
//	          }else if(bc[i] instanceof Group){
//	        	  bcchildren=((Group)bc[i]).getMembers().getValue();
//	          }
//	          else {
//	            bcchildren[0] = (Role)bc[i];
//	          }
//
//	          for (int j = 0; (bcchildren != null) && (j < bcchildren.length); ++j) {
//	            BaseClass[] bcuser = ((ContentManagerServiceStub)this.getClient().getService("ContentManagerService")).query(
//	              new SearchPathMultipleObject(
//	              bcchildren[j].getSearchPath().getValue()), props, 
//	              sortArray, new QueryOptions());
//	            String mudid=bcuser[0].getSearchPath().getValue();
//	            if(mudid!=null){
//	            	mudid=mudid.substring(mudid.indexOf("uid="));
//		            int index1=mudid.indexOf(",");
//		            int index2=mudid.indexOf(")");
//		            mudid=mudid.substring("uid=".length(),Math.min(index1, index2));
//	            }
//	            String emailName=bcuser[0].getDefaultName().getValue();
//	            if(mudid!=null||!mudid.equals("")){
//	            	emailName=mudid;
//	            }
//	            CogUser cu = new CogUser();
//	            cu.setCoguser_name(
//	              bcuser[0].getDefaultName().getValue());
//	            cu.setCoguser_searchpath(
//	              bcuser[0].getSearchPath().getValue());
//	            cu.setCoguser_email(
//	            		emailName + 
//	              "@gsk.com");
//	            this.userlist.add(cu);
//	          }
//	        }
//	      }
//	      catch (Exception e) {
//	        e.printStackTrace();
//	      }
//	    }
//	  }
//
//	  public List<CogUser> getUserlist() {
//	    return this.userlist;
//	  }
//
//	  public void setUserlist(List<CogUser> userlist) {
//	    this.userlist = userlist;
//	  }
}
